﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace MessengerBot
{
    /// <summary>
    /// This <see cref="ILogger"/> implementation implements the log
    /// destination handling by calling an event. This allows for easy
    /// mockups and test code.
    /// </summary>
    public sealed class EventBasedLogger : LoggerBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="EventBasedLogger"/> class.
        /// </summary>
        public EventBasedLogger()
            : this(null, null)
        {
            // Do nothing here
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="EventBasedLogger"/> class.
        /// </summary>
        /// <param name="eventHandler">
        /// The event handler that will be called when logging a message to the destination.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <para><paramref name="eventHandler"/> is <c>null</c>.</para>
        /// </exception>
        public EventBasedLogger(EventHandler<LogEntryEventArgs> eventHandler)
            : this(null, eventHandler)
        {
            // Do nothing here
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="EventBasedLogger"/> class.
        /// </summary>
        /// <param name="filter">A predicate that takes a <see cref="LogEntry"/> value and has
        /// to return <c>true</c> for the log entry to be sent to the
        /// log destination.</param>
        public EventBasedLogger(Predicate<LogEntry> filter)
            : this(filter, null)
        {
            // Do nothing here
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="EventBasedLogger"/> class.
        /// </summary>
        /// <param name="filter">A predicate that takes a <see cref="LogEntry"/> value and has
        /// to return <c>true</c> for the log entry to be sent to the
        /// log destination.</param>
        /// <param name="eventHandler">
        /// The event handler that will be called when logging a message to the destination.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <para><paramref name="eventHandler"/> is <c>null</c>.</para>
        /// </exception>
        public EventBasedLogger(Predicate<LogEntry> filter, EventHandler<LogEntryEventArgs> eventHandler)
            : base(filter)
        {
            if (eventHandler == null)
                throw new ArgumentNullException("eventHandler");

            MessageLogged += eventHandler;
        }

        /// <summary>
        /// This event will be fired in order to log the message to the log destination.
        /// </summary>
        public event EventHandler<LogEntryEventArgs> MessageLogged;

        /// <summary>
        /// Raises the <see cref="MessageLogged"/> event.
        /// </summary>
        /// <param name="e">The <see cref="MessengerBot.LogEntryEventArgs"/> instance containing the event data.</param>
        public void OnMessageLogged(LogEntryEventArgs e)
        {
            EventHandler<LogEntryEventArgs> handler = MessageLogged;
            if (handler != null)
                handler(this, e);
        }

        /// <summary>
        /// When implemented in a descendant, will output the log message to the log destination.
        /// </summary>
        /// <param name="level">The level of the message.</param>
        /// <param name="message">The message to log.</param>
        protected override void WriteToLog(LogLevel level, string message)
        {
            OnMessageLogged(new LogEntryEventArgs(new LogEntry(level, message)));
        }
    }
}